<template>
  <div>
    {{ content }}
    <button @click="insertTable(3, 3)">插入表格</button>
    <button @click="addColumn">添加列</button>
    <button @click="addRow">添加行</button>
    <button @click="deleteTable">删除表格</button>
    <button @click="mergeCells">合并单元格</button>
    <button @click="splitCell">拆分单元格</button>
    <button @click="deleteRow" :disabled="!canDeleteRow">删除行</button>
    <button @click="deleteColumn" :disabled="!canDeleteColumn">删除列</button>
    <br />
    <button @click="insertWord">插入一段话</button>
    <button @click="undo">撤销</button>
    <input v-model="replacementText" placeholder="输入替换内容" />
    <button @click="checkWordAndChange">取得选中的内容并替换</button>
    <button @click="findWordAndChange">模拟右侧抽屉替换</button>
    <input type="file" accept=".docx" @change="handleFileUpload" />
    <br />
    <!-- <button @click="insertMarkDown">模拟markdown数据</button>
    <button @click="exportMarkDown">导出markdown数据</button> -->
    <button @click="setAlignment('left')">靠左</button>
    <button @click="setAlignment('center')">居中</button>
    <button @click="setAlignment('right')">靠右</button>
    <button @click="turnBold">加粗</button>
    <button @click="turnBold">加粗</button>
    <button @click="setColor('#00FF00')">颜色</button>
    字体大小
    <select name="fruits" v-model="fontsize" @change="setFontSize">
      <option value="12">12px</option>
      <option value="14">14px</option>
      <option value="16">16px</option>
      <option value="18">18px</option>
      <option value="20">20px</option>
    </select>
    <button @click="exportToWord">导出为 Word</button>

    <div class="mainContent">
      <div class="toc-sidebar">
        <div
          v-for="item in tocItems"
          :key="item.id"
          :style="{ paddingLeft: (item.level - 2) * 20 + 'px' }"
          class="toc-item"
          @click="scrollToHeading(item.id)"
        >
          {{ item.text }}
        </div>
      </div>
      <div ref="editorElement" class="editorElement">
        <!-- 浮动菜单 -->
        <div v-show="toggleMenuFlag" class="menu-wrap">
          <button @click="editor.chain().focus().toggleBold().run()">
            加粗
          </button>
          <button @click="toggleUnderline">下划线</button>
          <button @click="startAI">AI智能</button>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import { Editor } from "@tiptap/vue-2";
import StarterKit from "@tiptap/starter-kit";
// import { Collaboration } from "@tiptap/extension-collaboration";
// import { CollaborationCursor } from "@tiptap/extension-collaboration-cursor";
// import * as Y from "yjs";
// import { WebsocketProvider } from "y-websocket";
import TableRow from "@tiptap/extension-table-row";
import TableHeader from "@tiptap/extension-table-header";
// import mammoth from "mammoth/mammoth.browser";
import draggableImage from "./js/draggable-image";
// import { CellSelection } from "prosemirror-tables";
import { markdownData } from "./js/markdown.js";
import { Node } from "@tiptap/core";
import Underline from "@tiptap/extension-underline";
import Color from "@tiptap/extension-color";
import Highlight from "@tiptap/extension-highlight";
import JSZip from "jszip";
import { DOMParser } from "xmldom";
// import { TextSelection } from "prosemirror-state";
import { exportAsDocx } from "./js/exportToWord.js";
import {
  TableCellMerge,
  HeadingWithId,
  CustomImage,
  // CustomTable,
  textAlign,
  tableCell,
  markDown,
  AlignableTable,
  textStyle,
  CustomParagraph,
  FontSize,
} from "./js/tipTapConfig.js";
export default {
  directives: { draggableImage },
  data() {
    return {
      toggleMenuFlag: false,
      editor: null,
      replacementText: "",
      isDragging: false,
      initialX: 0,
      initialY: 0,
      offsetX: 0,
      offsetY: 0,
      tocItems: [],
      styleMap: {},
      html: "",
      fontsize: "16",
      content: "",
      headings: [],
    };
  },
  mounted() {
    this.initializeEditor();
    // // 测试直接插入图片
    // this.editor.commands.setContent(
    // );
    this.showMenu();
  },
  computed: {
    canDeleteRow() {
      return this.isInTable && this.editor.can().deleteRow();
    },

    canDeleteColumn() {
      return this.isInTable && this.editor.can().deleteColumn();
    },

    isInTable() {
      return this.editor?.isActive("table");
    },
  },
  beforeDestroy() {
    this.editor.destroy();
  },

  methods: {
    initializeEditor() {
      // 创建 Yjs 文档
      // const ydoc = new Y.Doc();
      // // 创建 WebSocket 提供者
      // this.provider = new WebsocketProvider(
      //   "ws://localhost:1234",
      //   "room-name",
      //   ydoc
      // );

      const CustomDiv = Node.create({
        name: "customDiv",
        group: "block",
        content: "block*", // 允许内联内容
        parseHTML() {
          return [{ tag: "div" }];
        },
        renderHTML({ HTMLAttributes }) {
          return ["div", HTMLAttributes, 0];
        },
        addAttributes() {
          return {
            "data-id": {
              default: null, // 默认值
              parseHTML: (element) => element.getAttribute("data-id"), // 从 HTML 解析
              renderHTML: (attributes) => ({
                "data-id": attributes["data-id"],
              }), // 渲染到 HTML
            },
            class: {
              default: "custom-div",
              renderHTML: (attributes) => {
                return {
                  class: `${attributes.class}`,
                };
              },
            },
          };
        },
        // 禁止自动创建子节点
        addCommands() {
          return {
            createDiv:
              () =>
              ({ commands }) => {
                return commands.insertContent({ type: this.name }); // 插入纯 div 节点
              },
          };
        },
      });
      this.editor = new Editor({
        element: this.$refs.editorElement,
        extensions: [
          StarterKit.configure({
            paragraph: {
              content: "inline*", // 允许段落直接包含文本
            },
          }),
          CustomDiv,
          textAlign,
          // 关键修复 1：正确配置 Image 扩展
          CustomImage,
          AlignableTable,
          // CustomTable,
          textStyle,
          TableRow,
          tableCell,
          TableHeader,
          TableCellMerge,
          HeadingWithId,
          CustomParagraph,
          markDown,
          Underline,
          FontSize,
          Color, // 启用颜色
          Highlight.configure({
            // 启用高亮
            multicolor: true, // 允许多种高亮颜色
          }),
          // yjs协同
          // Collaboration.configure({
          //   document: ydoc, // 绑定 Yjs 文档
          // }),
          // CollaborationCursor.configure({
          //   provider: this.provider, // 绑定 Yjs 提供者
          //   user: {
          //     name: "用户 " + Math.floor(Math.random() * 100), // 随机用户名
          //     color: "#" + Math.floor(Math.random() * 16777215).toString(16), // 随机颜色
          //   },
          // }),
        ],
        content: "<div class='note'>上传 Word 文档开始编辑...</div>",
        // 关键配置：启用 HTML 解析
        parseOptions: {
          preserveWhitespace: "full",
        },
      });
      this.editor.on("paste", ({ event }) => {
        this.handlePaste(event);
      });
      this.editor.on("update", () => {
        console.log("update======>");
        // this.updateToc();
        this.$nextTick(() => this.updateToc());
      });
      // 确保在编辑器内容更新后绑定事件
      this.editor.on("transaction", () => {
        // this.updateToc();
      });
    },
    async handleFileUpload(event) {
      console.time("start");
      const file = event.target.files[0];
      if (!file) return;
      const zip = new JSZip();
      const zipContent = await zip.loadAsync(file);
      // 读取 Word 主文档内容
      const [documentXml, relsXml, styleXml] = await Promise.all([
        zipContent.file("word/document.xml").async("text"),
        zipContent.file("word/_rels/document.xml.rels").async("text"),
        zipContent.file("word/styles.xml").async("text"),
      ]);

      // 在 handleFileUpload 方法中添加
      // const allFiles = Object.keys(zipContent.files);
      // console.log("ZIP 文件列表:", allFiles);

      const docParser = new DOMParser();
      const xmlDoc = docParser.parseFromString(documentXml, "text/xml");
      const relsDoc = new DOMParser().parseFromString(relsXml, "text/xml");
      const styleDoc = docParser.parseFromString(styleXml, "text/xml");
      const relationships = Array.from(
        relsDoc.getElementsByTagName("Relationship")
      );

      const body = xmlDoc.getElementsByTagName("w:body")[0];
      const body2 = styleDoc.getElementsByTagName("w:body")[0];
      console.log(body2, "bbbbbbbbbbbbbb");

      const nodess = await this.collectNodes(body);
      // for (const [i, value] of nodess.entries()) {
      //   if (nodess.length >= (i + 1) * 5000) {
      //     let arr = nodess.slice(i * 5000, (i + 1) * 5000);
      //     let content = await this.parseWordDocument(
      //       arr,
      //       zipContent,
      //       relationships
      //     );
      //     this.editor.commands.insertContent(content);
      //   } else {
      //     return;
      //   }
      // }

      // 解析内容并转换为 Tiptap 格式
      const content = await this.parseWordDocument(
        nodess,
        zipContent,
        relationships
      );
      // this.content = styleDoc;
      console.timeEnd("start");
      console.time("end");
      this.editor.commands.setContent(content);
      console.timeEnd("end");
    },
    async parseWordDocument(nodess, zipContent, relationships) {
      // const body = xmlDoc.getElementsByTagName("w:body")[0];
      // const paragraphs = Array.from(body.getElementsByTagName("w:p"));
      // const table = Array.from(body.getElementsByTagName("w:tbl"));

      // const allElements = Array.from(body.childNodes).filter(
      //   (child) => child.tagName === "w:tbl" || child.tagName === "w:p"
      // );

      // const nodess = this.collectNodes(body);
      let htmlContent = "";
      let isTOC = false; // 标记是否处于目录区域
      let tocEntries = []; // 存储目录项
      let headingName = [];
      for (const p of nodess) {
        let paragraphHtml = "";
        if (this.isTOCField(p)) {
          isTOC = true;
        } else {
          isTOC = false;
        }
        // 检测目录结束（段落包含 TOC 字段的结束标记）
        if (this.isTOCEnd(p)) {
          isTOC = false;
          // htmlContent += this.generateTOCHtml(tocEntries); // 生成目录 HTML
          tocEntries = [];
          console.log(headingName, "headingName");
          // return;
        }
        // 处理目录项
        if (isTOC) {
          const entry = this.parseTOCEntry(p);
          if (entry) {
            headingName.push(entry.title);
            tocEntries.push(entry);
            if (
              entry.title ==
              "勘察设计单位：中国能源建设集团江苏省电力设计院有限公司"
            ) {
              console.log(p, "entry.titleentry.title");
            }
            htmlContent += this.generateTOCHtml(entry);
          } // 生成目录 HTML
        } else if (p.tagName === "w:tbl") {
          const rows = [];
          Array.from(p.getElementsByTagName("w:tr")).forEach((tr) => {
            const cells = [];
            Array.from(tr.getElementsByTagName("w:tc")).forEach((tc) => {
              // 处理单元格合并
              const gridSpan =
                tc
                  .getElementsByTagName("w:gridSpan")[0]
                  ?.getAttribute("w:val") || 1;
              const vMerge = tc
                .getElementsByTagName("w:vMerge")[0]
                ?.getAttribute("w:val");
              // 提取文本与图片
              const content = [this.extractText(tc)].filter(Boolean).join("");
              cells.push({
                content,
                colspan: parseInt(gridSpan),
                rowspan: vMerge === "restart" ? 2 : 1, // 简化跨行处理
              });
            });
            rows.push(cells);
          });
          htmlContent += await this.buildHTMLTable(rows);
          // const rows = Array.from(p.getElementsByTagName("w:tr"));

          // let tableHtml = "<table>";
          // Array.from(rows).forEach((row) => {
          //   tableHtml += "<tr>";
          //   Array.from(row.getElementsByTagName("w:tc")).forEach((cell) => {
          //     tableHtml += `<td>${this.parseWordDocument(cell)}</td>`;
          //   });
          //   tableHtml += "</tr>";
          // });
          // htmlContent += `${tableHtml}</table>`;
        } else {
          const runs = Array.from(p.getElementsByTagName("w:r"));
          for (const element of runs) {
            // 解析图片
            const drawing = element.getElementsByTagName("w:drawing")[0];
            if (drawing) {
              const blip = drawing.getElementsByTagName("a:blip")[0];
              const imageId = blip?.getAttribute("r:embed");
              if (imageId) {
                const imagePath = await this.getImagePath(
                  relationships,
                  imageId
                );
                const imageFile = zipContent.file(imagePath);
                if (imageFile) {
                  const base64 = await imageFile.async("base64");
                  htmlContent += `<img src="data:image/png;base64,${base64}"/>`;
                  // this.editor.commands.insertContent({
                  //   type: "image",
                  //   attrs: { src: `data:image/png;base64,${base64}` },
                  // });
                }
              }
            } else if (
              element.tagName === "w:r" &&
              element?.parentNode?.parentNode?.parentNode?.parentNode
                ?.tagName != "w:tbl"
            ) {
              // 解析文本样式
              const textNode = element.getElementsByTagName("w:t")[0];
              const text = textNode?.textContent || "";
              const styles = this.parseRunStyles(element); // 核心：提取样式
              // 生成带样式的 HTML
              let styledText = text;
              if (styles) {
                styledText = `<span style="${styles}">${styledText}</span>`;
              }
              // 处理加粗、斜体（兼容原有逻辑）
              const isBold = element.getElementsByTagName("w:b").length > 0;
              const isItalic = element.getElementsByTagName("w:i").length > 0;
              if (isBold) styledText = `<strong>${styledText}</strong>`;
              if (isItalic) styledText = `<em>${styledText}</em>`;

              paragraphHtml += styledText;
            } else if (element.tagName === "w:numPr") {
              const listType =
                element.getElementsByTagName("w:ilvl")[0]?.textContent;
              const listHtml = listType
                ? `<li>${paragraphHtml}</li>`
                : paragraphHtml;
              htmlContent += `<ul>${listHtml}</ul>`;
            }
          }
          const paraStyles = this.parseParagraphStyles(p);
          if (paraStyles) {
            paragraphHtml = `<p style="${paraStyles}">${paragraphHtml}</p>`;
          }
          // 处理标题层级（原有逻辑）
          const headingLevel = this.getHeadingLevel(p, headingName);
          if (headingLevel) {
            const styles = this.parseRunStyles(p);

            htmlContent += `<h${headingLevel} style="${styles}">${p.textContent}</h${headingLevel}>`;
          } else {
            htmlContent += `<p>${paragraphHtml}</p>`;
          }
        }
      }
      return htmlContent;
    },
    // 获取图片路径
    async getImagePath(relationships, imageId) {
      const rel = await relationships.find(
        (r) => r.getAttribute("Id") === imageId
      );
      if (!rel) {
        console.error(`未找到关系 ID: ${imageId}`);
        return null;
      }
      const target = await rel.getAttribute("Target");

      // 修正路径逻辑（示例）
      const imagePath = await target.replace(/^media\//, "word/media/"); // 将 "../media" 转换为 "word/media"
      return imagePath;
    },
    generateTOCHtml(entry) {
      let html = "";
      html += `<div class="toc-style" style="margin-left: ${entry.indent}px">
          <div class='tit'>${entry.title}</div>
          <div class='circle'></div>
          <div class='page'>${entry.num}</div>
      </div>`;
      return html;
    },
    // 检测是否为 TOC 字段起始标记
    isTOCField(paragraph) {
      console.log(paragraph, paragraph.textContent, "paragraph");

      const fldChar = paragraph.getElementsByTagName("w:fldChar")[0];
      return fldChar?.getAttribute("w:fldCharType") === "begin";
    },
    // 检测是否为 TOC 字段结束标记
    isTOCEnd(paragraph) {
      const fldChar = paragraph.getElementsByTagName("w:fldChar")[0];
      return fldChar?.getAttribute("w:fldCharType") === "end";
    },
    parseTOCEntry(paragraph) {
      // 提取超链接锚点和文本
      const textNodes = Array.from(paragraph.getElementsByTagName("w:t"));
      // 分离标题和页码（假设用制表符分隔）
      let title = "",
        num = "";
      num =
        textNodes[textNodes.length - 1]?.textContent.trim() ||
        textNodes[textNodes.length - 2]?.textContent.trim();

      textNodes.forEach((node) => {
        const text = node.textContent;
        if (text != num) {
          title += text;
        }
      });

      // 提取缩进层级（通过 w:ind 或 w:numPr）
      const indent = this.getIndentLevel(paragraph);
      const level = this.getHeadingLevel2(paragraph); // 通过标题级别或编号层级

      return { title: title.trim(), indent, level, num };
    },

    // 获取缩进值（单位：缇 → 转换为像素）
    getIndentLevel(paragraph) {
      const ind = paragraph.getElementsByTagName("w:ind")[0];
      const left = ind?.getAttribute("w:left");
      return left ? Math.floor((parseInt(left) / 1440) * 96) : 0; // 1缇=1/1440英寸，96dpi
    },

    // 获取标题层级（通过 w:numPr 或段落样式）
    getHeadingLevel2(paragraph) {
      const numPr = paragraph.getElementsByTagName("w:numPr")[0];
      if (numPr) {
        const ilvl = numPr.getElementsByTagName("w:ilvl")[0];
        return parseInt(ilvl?.getAttribute("w:val")) + 1; // w:ilvl 从0开始
      }
      // 备用方案：通过段落样式名判断（如 Heading1）
      const pStyle = paragraph.getElementsByTagName("w:pStyle")[0];
      const styleName = pStyle?.getAttribute("w:val") || "";
      return styleName.replace("Heading", "") || 1;
    },
    // 解析单个 <w:r> 元素的样式（如颜色、字体）
    parseRunStyles(runElement) {
      const rPr = runElement.getElementsByTagName("w:rPr")[0];
      if (!rPr) return "";

      const styles = [];
      // 文字颜色
      const colorNode = rPr.getElementsByTagName("w:color")[0];
      if (colorNode) {
        const colorVal = colorNode.getAttribute("w:val");
        styles.push(`color: #${this.wordColorToHex(colorVal)}`);
      }

      // 背景色（高亮）
      const highlightNode = rPr.getElementsByTagName("w:highlight")[0];
      if (highlightNode) {
        const highlightVal = highlightNode.getAttribute("w:val");
        styles.push(`background-color: #${this.wordColorToHex(highlightVal)}`);
      }

      // 字体大小（单位：磅 -> px）
      const fontSizeNode = rPr.getElementsByTagName("w:sz")[0];
      if (fontSizeNode) {
        const pt = parseInt(fontSizeNode.getAttribute("w:val")) / 2; // 1pt = 1/72英寸 ≈ 1.333px
        styles.push(`font-size: ${Math.round(pt * 1.333)}px`); // 或转换为 px: Math.round(pt * 1.333) + 'px'
      }

      // 字体类型
      const fontNode = rPr.getElementsByTagName("w:rFonts")[0];
      if (fontNode) {
        const fontName = fontNode.getAttribute("w:ascii");
        styles.push(`font-family: ${fontName}`);
      }

      return styles.join("; ");
    },

    // 解析段落样式（如对齐）
    parseParagraphStyles(paragraph) {
      const pPr = paragraph.getElementsByTagName("w:pPr")[0];
      if (!pPr) return "";

      const styles = [];
      // 对齐方式
      const alignNode = pPr.getElementsByTagName("w:jc")[0];
      if (alignNode) {
        const alignVal = alignNode.getAttribute("w:val");
        styles.push(`text-align: ${alignVal}`);
      }

      return styles.join("; ");
    },

    // 将 Word 颜色值转换为 HEX（如 'FF0000' -> 'FF0000'）
    wordColorToHex(wordColor) {
      // Word 颜色值可能为自动（auto）或预设名称（如 'red'），需特殊处理
      if (!wordColor || wordColor === "auto") return "000000"; // 默认黑色
      return wordColor.startsWith("FF") ? wordColor.slice(2) : wordColor;
    },

    // 获取标题层级（示例：根据样式名判断）
    getHeadingLevel(paragraph, headingName) {
      const isHeading = headingName.includes(paragraph?.textContent?.trim());
      const styleNode = paragraph.getElementsByTagName("w:pStyle")[0];
      const styleId = styleNode?.getAttribute("w:val") || "";
      return styleId.startsWith("Heading") || isHeading
        ? styleId.replace("Heading", "")
        : null;
    },
    // 读取文件为ArrayBuffer
    readFile(file) {
      return new Promise((resolve) => {
        const reader = new FileReader();
        reader.onload = () => resolve(reader.result);
        reader.readAsArrayBuffer(file);
      });
    },
    // ✅ 处理粘贴事件
    async handlePaste(event) {
      const items = event.clipboardData.items;
      for (const item of items) {
        if (item.type.startsWith("image")) {
          event.preventDefault();
          const blob = item.getAsFile();
          const base64 = await this.blobToBase64(blob);
          this.insertImage(base64);
          return;
        }
      }
    },
    // ✅ Blob 转 Base64
    blobToBase64(blob) {
      return new Promise((resolve) => {
        const reader = new FileReader();
        reader.onload = () => resolve(reader.result);
        reader.readAsDataURL(blob);
      });
    },

    // ✅ 插入图片到编辑器
    insertImage(src) {
      this.editor
        .chain()
        .focus()
        .insertContent({
          type: "image",
          attrs: {
            src,
            width: "300px",
            height: "auto",
          },
        })
        .run();
    },
    // 插入文字
    insertWord() {
      this.editor.chain().focus().insertContent("插入一段话············").run();
    },
    // 撤回上次操作
    undo() {
      this.editor.chain().focus().undo().run();
    },
    // 选中文字并替换
    checkWordAndChange() {
      if (!this.replacementText) return;
      if (!this.editor.state.selection.empty) {
        const { state } = this.editor;
        const { from, to } = state.selection;

        if (from === to) return;

        const textNode = state.schema.text(
          this.replacementText,
          state.selection.$head.marks() // 获取光标位置格式
        );

        const tr = state.tr.replaceWith(from, to, textNode);
        this.editor.view.dispatch(tr);
      } else {
        alert("请先选中要替换的文本");
      }
    },
    // 模拟右侧抽屉段落替换
    findWordAndChange() {
      if (!this.replacementText) return;
      const { state } = this.editor;
      const { doc } = state;
      let findText = this.replacementText;
      let replaceText = "替换后";
      let offset = 0;
      // 遍历文档中的所有节点，找到所有文本节点
      // 遍历文档中的所有节点
      doc.descendants((node, pos) => {
        if (node.isText) {
          const text = node.text;
          let index = text.indexOf(findText);
          while (index !== -1) {
            const from = pos + index + offset;
            const to = from + findText.length;
            // 执行替换操作
            this.editor
              .chain()
              .focus()
              .deleteRange({ from, to })
              .insertContentAt(from, replaceText)
              .run();

            // 更新偏移量，考虑替换文本的长度
            offset += replaceText.length - findText.length;
            // 继续查找下一个匹配项
            index = text.indexOf(findText, index + 1);
          }
        }
        return true;
      });
    },
    // 插入表格
    insertTable(rows, cols) {
      this.editor
        .chain()
        .focus()
        .insertTable({ rows, cols, withHeaderRow: false })
        .run();
    },
    // 新增列
    addColumn() {
      this.editor.chain().focus().addColumnAfter().run();
    },
    addRow() {
      this.editor.chain().focus().addRowAfter().run();
    },
    deleteTable() {
      this.editor.chain().focus().deleteTable().run();
    },
    mergeCells() {
      this.editor.chain().focus().mergeCells().run();
    },
    splitCell() {
      this.editor.chain().focus().splitCell().run();
    },
    deleteRow() {
      this.editor.chain().focus().deleteRow().run();
    },
    deleteColumn() {
      this.editor.chain().focus().deleteColumn().run();
    },
    turnBold() {
      this.editor.chain().focus().toggleBold().run();
    },
    toggleUnderline() {
      this.editor.chain().focus().toggleUnderline().run();
    },
    setFontSize() {
      console.log(this.fontsize, "this.fontsize");
      this.editor.chain().focus().setFontSize(this.fontsize).run();
    },

    updateToc() {
      const headings = [];
      const transaction = this.editor.state.tr;
      // 遍历文档节点
      this.editor.state.doc.descendants((node, pos) => {
        console.log(node, node.textContent, "textContent");
        if (node.type?.name === "heading") {
          const id = this.generateID(node.textContent);
          // 添加锚点ID
          if (!node.attrs.id) {
            transaction.setNodeMarkup(pos, undefined, {
              ...node.attrs,
              id,
            });
          }
          headings.push({
            level: node.attrs.level,
            text: node?.content?.content?.[0].textContent,
            id: node.attrs.id || id,
          });
        }
        if (
          node.attrs?.class != "toc-style" &&
          node.textContent == "变电站基本情况"
        ) {
          console.log(node, "nnnnnnnnnnnn");
        }
      });

      // 提交事务更新节点属性
      transaction.setMeta("preventUpdate", true);
      this.editor.view.dispatch(transaction);

      this.tocItems = headings;
    },
    // 生成唯一ID
    generateID(text) {
      return text
        .toLowerCase()
        .replace(/[^a-z0-9]+/g, "-")
        .replace(/(^-|-$)/g, "");
    },
    // 滚动到对应标题
    scrollToHeading(id) {
      const element = document.getElementById(id);
      if (element) {
        element.scrollIntoView({
          behavior: "smooth",
          block: "start",
        });
      }
    },
    // 导入Markdown数据
    insertMarkDown() {
      this.editor.commands.setContent(markdownData);
    },
    // 导出markdown数据
    exportMarkDown() {
      const markdownOutput = this.editor.storage.markdown.getMarkdown();
      console.log(markdownOutput);
    },
    async setAlignment(align) {
      // 统一处理所有元素对齐
      if (this.editor.isActive("image")) {
        this.editor.chain().focus().updateAttributes("image", { align }).run();
      } else if (this.editor.isActive("table")) {
        console.log(this.editor.chain().focus(), "ttt");
        this.editor.chain().focus().setTextAlign(align).run();
      } else {
        this.editor.chain().focus().setTextAlign(align).run();
      }
    },
    exportToWord() {
      // 获取 Tiptap 的 HTML 内容
      const html = this.editor.getHTML(); // 调用导出函数
      exportAsDocx(html, "tiptap-content.docx");
    },
    recursiveGetElementsByTagName(rootNode, targetTags) {
      const results = [];
      // 递归遍历函数
      function traverse(node) {
        console.log(targetTags.includes(node.tagName.toLowerCase()));

        // 检查当前节点是否符合条件（注意XML标签名大小写敏感性）
        if (targetTags.includes(node.tagName.toLowerCase())) {
          results.push(node);
        }
        // 递归处理子节点
        const children = node.children || [];
        for (const child of children) {
          traverse(child); // 深度优先遍历
        }
      }
      traverse(rootNode);
      return results;
    },
    collectNodes(node, results = []) {
      if (node.tagName === "w:p" || node.tagName === "w:tbl") {
        results.push(node);
      }
      Array.from(node.childNodes || []).forEach((child) =>
        this.collectNodes(child, results)
      );
      return results;
    },
    // 文本提取
    extractText(cell) {
      return Array.from(cell.getElementsByTagName("w:t"))
        .map((t) => t.textContent)
        .join(" ");
    },
    // 构建 HTML 表格
    buildHTMLTable(rows) {
      return `<table border="1" style="border-collapse:collapse">
        <tbody>
          ${rows
            .map(
              (row) =>
                `<tr>${row
                  .map(
                    (cell) =>
                      `<td colspan="${cell.colspan}" rowspan="${cell.rowspan}">${cell.content}</td>`
                  )
                  .join("")}</tr>`
            )
            .join("")}
        </tbody>
      </table>`;
    },
    // 绑定点击事件，出菜单
    showMenu() {
      // 获取编辑器根元素
      const editorElement = this.editor.view.dom;
      const menu = document.querySelector(".menu-wrap");
      const parent = document.querySelector(".editorElement");
      let downx;
      let downy;
      editorElement.addEventListener("mousedown", (e) => {
        console.log("鼠标位置====");
        const { clientX, clientY } = e;
        const rect = parent.getBoundingClientRect();
        // 步骤3: 计算基础相对坐标
        downx = clientX - rect.left;
        downy = clientY - rect.top;

        // 步骤4: 处理父元素自身滚动偏移
        downx += parent.scrollLeft;
        downy += parent.scrollTop;
        // 处理所有祖先元素的滚动偏移
        let current = parent.parentElement;
        while (current && current !== document.documentElement) {
          downx += current.scrollLeft;
          downy += current.scrollTop;
          current = current.parentElement;
        }
        // 步骤5: 修正边框影响
        const style = getComputedStyle(parent);
        const borderLeft = parseFloat(style.borderLeftWidth) || 0;
        const borderTop = parseFloat(style.borderTopWidth) || 0;
        downx -= borderLeft;
        downy -= borderTop;

        // 步骤6: 返回结果
        console.log("11111", "down-x:" + downx, ",down-y:" + downy);
      });

      // 添加鼠标抬起监听
      editorElement.addEventListener("mouseup", (event) => {
        const { from, to, empty } = this.editor.state.selection;
       if (!empty && from !== to) {
          const { clientX, clientY } = event;
          const rect = parent.getBoundingClientRect();
          // 步骤3: 计算基础相对坐标
          let x = clientX - rect.left;
          let y = clientY - rect.top;

          // 步骤4: 处理父元素自身滚动偏移
          x += parent.scrollLeft;
          y += parent.scrollTop;
          // 处理所有祖先元素的滚动偏移
          let current = parent.parentElement;
          while (current && current !== document.documentElement) {
            x += current.scrollLeft;
            y += current.scrollTop;
            current = current.parentElement;
          }
          // 步骤5: 修正边框影响
          const style = getComputedStyle(parent);
          const borderLeft = parseFloat(style.borderLeftWidth) || 0;
          const borderTop = parseFloat(style.borderTopWidth) || 0;
          x -= borderLeft;
          y -= borderTop;

          // 步骤6: 返回结果
          console.log("11111", "x:" + x, ",y:" + y);
          let realX = x < downx ? x : downx;
          let realy = y < downy ? y : downy;
          menu.style.top = `${realy - 55}px`;
          menu.style.left = `${realX}px`;
          this.toggleMenuFlag = true;
        } else {
          this.toggleMenuFlag = false;
          console.warn("请选中文本---");
        }
      });
    },
    startAI() {
      console.log("开始AI智能逻辑===");
    },
    setColor(color) {
      this.editor.chain().focus().setColor(color).run()
    }
  },
};
</script>

<style scoped>
/* 组件样式 */
</style>

<style lang="scss">
.mainContent {
  display: flex;
  height: 545px;
  .toc-sidebar {
    width: 20%;
    overflow-y: scroll;
    .toc-item {
      white-space: nowrap;
      text-align: left;
      text-overflow: ellipsis;
      overflow: hidden;
      cursor: pointer;
      margin: 4px 0;
    }
  }
  .editorElement {
    flex: 1;
    overflow-y: scroll;
  }
}
/* 全局文档样式 */
.doc-paragraph {
  margin: 12px 0;
  line-height: 1.6;
  font-family: "SimSun", serif;
}

/* 表格样式 */
table {
  border-collapse: collapse;
  margin: 1rem 0;
  table-layout: fixed;
  max-width: 100% !important;
}

td,
th {
  padding: 8px;
  min-width: 50px;
  position: relative;
  vertical-align: top;
}

th {
  font-weight: bold;
}

/* 合并单元格提示 */
[colspan]:not([colspan="1"]),
[rowspan]:not([rowspan="1"]) {
  background-color: #f0f8ff;
}

/* 列宽调整手柄 */
.column-resize-handle {
  position: absolute;
  right: 0;
  top: 0;
  bottom: 0;
  width: 4px;
  background-color: #adf;
  pointer-events: none;
  cursor: pointer;
}

img {
  max-width: 100%;
  height: auto;
  border: 1px solid red !important; /* 调试用边框 */
}
/* 全局样式或组件内样式 */
.editor-image {
  border: 1px solid #ddd !important; /* 调试用边框 */
}

/* 覆盖潜在冲突样式 */
.ProseMirror {
  width: 100%;
  padding: 20px 12px;
  box-sizing: border-box;
  img {
    max-wdith: 100% !important;
  }
  .tableWrapper {
    display: flex;
    align-items: center;
  }
  table {
    border-collapse: collapse;
    border: 1px solid #000;
    margin: 5px;
  }
  td,
  td {
    border: 1px solid #9e9797; /* 边框颜色和粗细 */
    padding: 8px; /* 内边距 */
  }
  h1,
  h2,
  h3,
  h4,
  h5 {
    font-size: 16px;
    text-align: left;
    margin: 12px 0;
  }
  h1 {
    text-indent: 15px;
  }
  h2 {
    text-indent: 25px;
  }
  h3,
  h4,
  h5 {
    text-indent: 15px;
  }
  p,
  div {
    text-align: left;
    text-indent: 20px;
  }
  p {
    margin: 12px 0;
  }
  div {
    line-height: 20px;
  }
  ul {
    list-style-type: lower-alpha;
  }
  .toc1 {
    text-indent: 10px;
  }
  .toc2 {
    text-indent: 20px;
  }
  .toc3 {
    text-indent: 30px;
  }
  .toc4 {
    text-indent: 40px;
  }
  .text-center {
    text-align: center;
    font-size: 20px;
    font-weight: 700;
    margin: 20px 0;
  }
  .ul-list {
    text-indent: 50px;
    line-height: 22px;
  }
  .note {
    p {
      text-align: center !important;
    }
  }
  .toc-style {
    display: flex;
    justify-content: space-between;
    align-items: center;
    p {
      margin: 0;
    }
    .tit {
      width: fit-content;
    }
    .circle {
      flex: 1;
      height: 0;
      border-bottom: 2px dotted #918787;
      p {
        text-align: justify !important; /* 两端对齐 */
        overflow: hidden; /* 隐藏溢出部分 */
      }
    }
    .page {
      width: 35px;
      p {
        width: 100%;
        text-align: right !important;
        white-space: nowrap;
        text-indent: 0;
      }
    }
  }
}
/* ✅ 确保图片可见性 */
.resizable-image {
  display: block !important;
  max-width: 100%;
  height: auto;
  margin: 10px auto;
  position: relative !important;
}

.resizable-image::after {
  content: "";
  position: absolute;
  bottom: -8px;
  right: -8px;
  width: 16px;
  height: 16px;
  background: #2196f3;
  border-radius: 50%;
  cursor: nwse-resize;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
button {
  margin: 5px;
}

/* 统一对齐样式 */
.ProseMirror {
  p[data-text-align],
  h1[data-text-align],
  h2[data-text-align] {
    &[data-text-align="left"] {
      text-align: left;
    }
    &[data-text-align="center"] {
      text-align: center;
    }
    &[data-text-align="right"] {
      text-align: right;
    }
  }

  /* 图片浮动处理 */
  .float-image {
    max-width: 60%;
    &[data-align="left"] {
      float: left;
      margin: 0 1rem 1rem 0;
    }
    &[data-align="right"] {
      float: right;
      margin: 0 0 1rem 1rem;
    }
    &[data-align="center"] {
      display: block;
      margin: 1rem auto;
    }
  }
}

/* 清除浮动 */
.ProseMirror::after {
  content: "";
  display: table;
  clear: both;
}
</style>
